﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web;

namespace CloudClip.ExtensionMethod
{
    public static class ReflectionManager
    {
        /// <summary>
        /// 依據Type建立物件
        /// </summary>
        /// <param name="tType">this is a book</param> 
        /// <returns>object</returns>
        public static T CreateObject<T>(this Type tType)
        {
            //依參數建立一個物件
            return (T)Activator.CreateInstance(tType);
        }

        /// <summary>
        /// 依據ObjectIdentityString產生物件
        /// </summary>
        /// <param name="sObjectIdentity">AssemblyName|TypeName</param>
        /// <returns>回傳的物件</returns>
        public static T CreateObjectByObjectIdentityString<T>(this string sObjectIdentity)
        {
            try
            {
                char cSplitChar = Convert.ToChar("|");
                string[] arSplit = sObjectIdentity.Split(cSplitChar);

                return (T)Assembly.Load(arSplit[0]).CreateInstance(arSplit[1]);
            }
            catch (FileNotFoundException)
            {
                throw new Exception(sObjectIdentity);
            }
        }

        /// <summary>
        /// 取得傳入物件的AssemblyName|TypeName
        /// </summary>
        /// <param name="oObject">物件</param>
        /// <returns>物件的AssemblyName|TypeName</returns>
        public static string GetObjectIdentityString(this object oObject)
        {
            //將this.GetType().FullName)與this.GetType().Assembly.FullName合併後傳回　(中間以 |　為分隔)
            string sAssemblyFullName = oObject.GetType().Assembly.FullName;
            if (sAssemblyFullName.ToLower().Contains("app_web"))
            {
                string sReplace = sAssemblyFullName.Substring(7, 9);

                sAssemblyFullName = sAssemblyFullName.Replace(sReplace, string.Empty);
            }
            return sAssemblyFullName + "|" + oObject.GetType().FullName;
        }

        /// <summary>
        /// 取得傳入Type的 AssemblyName|TypeName
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns>AssemblyName|TypeName</returns>
        public static string GetObjectIdentityString(this Type type)
        {
            string sAssemblyFullName = type.Assembly.FullName;
            if (sAssemblyFullName.ToLower().Contains("app_web"))
            {
                string sReplace = sAssemblyFullName.Substring(7, 9);

                sAssemblyFullName = sAssemblyFullName.Replace(sReplace, string.Empty);
            }

            return sAssemblyFullName + "|" + type.FullName;
        }



        ///// <summary>
        ///// 到指定的目錄,取出所有屬於該Type的Type資訊
        ///// </summary>
        ///// <param name="sAssemblyFolderNamePath">組件所在的目錄</param>
        ///// <param name="tQueryType">查詢的型別</param>
        ///// <returns>所有繼承或實作該型別的類別</returns>
        //public List<Type> QueryObjectByType(string sAssemblyFolderNamePath, Type tQueryType)
        //{
        //    //到參數的目錄,取出Type為tQueryType的項目
        //    DirectoryInfo dirSpcPath = new DirectoryInfo(sAssemblyFolderNamePath);

        //    if (!dirSpcPath.Exists)
        //    {
        //        //throw new Exception(_Res.ReflectionManager_QueryObjectByType + sAssemblyFolderNamePath);
        //    }

        //    List<Type> lstReflectionItem = new List<Type>();

        //    //QQ Hugo [ReflectionDB] 1.請拋出路徑錯誤的的錯誤，需標明路徑 (Hunt)
        //    //QQ Hunt OK
        //    foreach (FileInfo fiDllFile in dirSpcPath.GetFiles("*.dll"))
        //    {
        //        try
        //        {
        //            Assembly loadAssembly = Assembly.LoadFile(fiDllFile.FullName);

        //            foreach (Type aType in loadAssembly.GetTypes())
        //            {
        //                if (tQueryType.IsAssignableFrom(aType))
        //                {
        //                    lstReflectionItem.Add(aType);
        //                }
        //            }
        //        }
        //        catch (BadImageFormatException)
        //        {
        //            //理論上不是.NET DLL的，應該跑這個Exception
        //        }
        //        catch (ReflectionTypeLoadException)
        //        {
        //            //QQ Hugo [ReflectionDB] 1.此不明的錯誤會造成傳回結果上的錯誤嗎(應取得未取得)？ (Hunt)
        //            //QQ Hunt 有些.NET 的Dll載入時會拋出這個訊息
        //        }
        //    }

        //    return lstReflectionItem;
        //}

        ///// <summary>
        ///// 到目前Assembly所在的目錄(bin),取出所有屬於該Type的Type資訊
        ///// </summary>
        ///// <param name="tQueryType">欲查詢的型別</param>
        ///// <returns>所有繼承或實作該型別的類別</returns>
        //public List<Type> QueryObjectByType(Type tQueryType)
        //{
        //    //到目前Assembly所在的目錄(bin),取出Type為tQueryType的項目
        //    string sPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin\\");
        //    return QueryObjectByType(sPath, tQueryType);

        //    //return QueryObjectByType(AppDomain.CurrentDomain.BaseDirectory, tQueryType);
        //}

        ///// <summary>
        ///// 到指定的目錄,取出所有屬於該Type的Type資訊
        ///// </summary>
        ///// <param name="sAssemblyFolderNamePath">組件所在的目錄</param>
        ///// <param name="sQueryType">型別的完整名稱</param>
        ///// <returns>所有繼承或實作該型別的類別</returns>
        //public List<Type> QueryObjectByTypeName(string sAssemblyFolderNamePath, string sQueryType)
        //{
        //    //到參數的目錄,取出Type為tQueryType的項目
        //    DirectoryInfo dirSpcPath = new DirectoryInfo(sAssemblyFolderNamePath);

        //    if (!dirSpcPath.Exists)
        //    {
        //        //throw new Exception(_Res.ReflectionManager_QueryObjectByType + sAssemblyFolderNamePath);
        //    }

        //    List<Type> lstReflectionItem = new List<Type>();
        //    Type baseType;

        //    //QQ Hugo [ReflectionDB] 1.請拋出路徑錯誤的的錯誤，需標明路徑 (Hunt)
        //    //QQ Hunt OK
        //    foreach (FileInfo fiDllFile in dirSpcPath.GetFiles("*.dll"))
        //    {
        //        try
        //        {
        //            Assembly loadAssembly = Assembly.LoadFile(fiDllFile.FullName);
        //            //取得基本型別，Interface or Abstract Class
        //            baseType = loadAssembly.GetType(sQueryType, false, true);

        //            if (baseType == null)
        //            {
        //                continue;
        //            }

        //            foreach (Type aType in loadAssembly.GetTypes())
        //            {
        //                if (baseType.IsAssignableFrom(aType))
        //                {
        //                    lstReflectionItem.Add(aType);
        //                }
        //            }
        //        }
        //        catch (BadImageFormatException)
        //        {
        //        }
        //        catch (ReflectionTypeLoadException)
        //        {
        //        }
        //    }

        //    return lstReflectionItem;
        //}

        ///// <summary>
        ///// 以檔案名稱+TypeName 取得哪些檔案繼承這個 Type
        ///// </summary>
        ///// <param name="sFileName">完整的路徑+檔案名稱(D:\ezGlobal\test.XML)</param>
        ///// <param name="sTypeName">typeof(XXX).FullName</param>
        ///// <param name="sTypeFilter">typeof(XXX).FullName的filter條件</param>
        ///// <returns>傳回List 內容為Type的集合</returns>
        //public List<Type> QueryObjectFromDLL(string sFileName, string sTypeName, string sTypeFilter)
        //{
        //    List<Type> lstReflectionItem = new List<Type>();
        //    Type baseType;

        //    try
        //    {
        //        FileInfo info = new FileInfo(sFileName);

        //        Assembly loadAssembly = Assembly.LoadFile(info.FullName);

        //        if (!sTypeName.IsNullOrEmpty())
        //        {
        //            //取得基本型別，Interface or Abstract Class
        //            baseType = loadAssembly.GetType(sTypeName, false, true);

        //            if (baseType != null)
        //            {
        //                foreach (Type aType in loadAssembly.GetTypes())
        //                {
        //                    if (baseType.IsAssignableFrom(aType) && TypeFilter(aType.Name, sTypeFilter))
        //                    {
        //                        lstReflectionItem.Add(aType);
        //                    }
        //                }
        //                return lstReflectionItem;
        //            }
        //        }

        //        foreach (Type aType in loadAssembly.GetTypes())
        //        {
        //            if (TypeFilter(aType.Name, sTypeFilter))
        //            {
        //                lstReflectionItem.Add(aType);
        //            }
        //        }
        //    }
        //    catch (BadImageFormatException)
        //    {
        //    }
        //    catch (ReflectionTypeLoadException)
        //    {
        //    }

        //    return lstReflectionItem;
        //}


        ///// <summary>
        ///// 到目前Assembly所在的目錄(bin),取出所有屬於該Type的Type資訊
        ///// </summary>
        ///// <param name="tQueryType">欲查詢的型別</param>
        ///// <returns>所有繼承或實作該型別的類別</returns>
        //public List<Type> QueryObjectByTypeLoadFrom(Type tQueryType)
        //{
        //    //到目前Assembly所在的目錄(bin),取出Type為tQueryType的項目
        //    string sBasePath = null;
        //    if (tQueryType.Assembly.Location != null)
        //    {
        //        FileInfo fileInfo = new FileInfo(new System.Uri(tQueryType.Assembly.CodeBase).LocalPath);
        //        sBasePath = fileInfo.DirectoryName;
        //    }
        //    string sPath = getCodePath(sBasePath);
        //    return QueryObjectByTypeLoadFrom(sPath, tQueryType);

        //    //return QueryObjectByType(AppDomain.CurrentDomain.BaseDirectory, tQueryType);
        //}

        //private static string getCodePath(string sBasePath)
        //{
        //    /*空字串處理機制(代表取預設執行目錄內的東西)*/
        //    if (sBasePath.IsNullOrEmpty())
        //    {
        //        //若是Web，則取base\bin，AP則取bin
        //        sBasePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
        //            HttpContext.Current == null ? "" : "bin");
        //        //但如果是在web中起新Thread，則HttpContext.Current會是null
        //        //所以不會取到正確的bin，因此要在往下取一層
        //        //也因此App下的不能再有一層bin
        //        if (HttpContext.Current == null)
        //        {
        //            if (computer.FileSystem.DirectoryExists(sBasePath))
        //            {
        //                string sBinPath = Path.Combine(sBasePath, "bin");
        //                if (computer.FileSystem.DirectoryExists(sBinPath))
        //                {
        //                    sBasePath = sBinPath;
        //                }
        //            }
        //        }

        //    }

        //    /*取得路徑(若是設定相對路徑，則於DomainPath相連)*/
        //    string sBaseDirectory;
        //    if (sBasePath.IndexOf(":") < 0)
        //        sBaseDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, sBasePath);
        //    else
        //        sBaseDirectory = sBasePath;


        //    /*判斷路徑是否存在*/
        //    if (!computer.FileSystem.DirectoryExists(sBaseDirectory))
        //        throw new etException(String.Format("Serach diretctory does not exist,Directory:{0} DirectoryPath:{1}", sBaseDirectory, System.AppDomain.CurrentDomain.BaseDirectory));


        //    return sBaseDirectory;
        //}

        ///// <summary>
        ///// 到指定的目錄,取出所有屬於該Type的Type資訊
        ///// </summary>
        ///// <param name="sAssemblyFolderNamePath">組件所在的目錄</param>
        ///// <param name="tQueryType">查詢的型別</param>
        ///// <returns>所有繼承或實作該型別的類別</returns>
        //public List<Type> QueryObjectByTypeLoadFrom(string sAssemblyFolderNamePath, Type tQueryType)
        //{
        //    //到參數的目錄,取出Type為tQueryType的項目
        //    DirectoryInfo dirSpcPath = new DirectoryInfo(sAssemblyFolderNamePath);

        //    if (!dirSpcPath.Exists)
        //    {
        //        throw new etException(sAssemblyFolderNamePath);
        //    }

        //    List<Type> lstReflectionItem = new List<Type>();

        //    //QQ Hugo [ReflectionDB] 1.請拋出路徑錯誤的的錯誤，需標明路徑 (Hunt)
        //    //QQ Hunt OK
        //    foreach (FileInfo fiDllFile in dirSpcPath.GetFiles("*.dll"))
        //    {
        //        try
        //        {
        //            Assembly loadAssembly = Assembly.LoadFrom(fiDllFile.FullName);

        //            foreach (Type aType in loadAssembly.GetTypes())
        //            {
        //                if (tQueryType.IsAssignableFrom(aType))
        //                {
        //                    lstReflectionItem.Add(aType);
        //                }
        //            }
        //        }
        //        catch (BadImageFormatException)
        //        {
        //            //理論上不是.NET DLL的，應該跑這個Exception
        //        }
        //        catch (ReflectionTypeLoadException)
        //        {
        //            //QQ Hugo [ReflectionDB] 1.此不明的錯誤會造成傳回結果上的錯誤嗎(應取得未取得)？ (Hunt)
        //            //QQ Hunt 有些.NET 的Dll載入時會拋出這個訊息
        //        }
        //    }

        //    return lstReflectionItem;
        //}

        ///// <summary>
        ///// 檢核是否符合過濾條件
        ///// </summary>
        ///// <param name="sTypeName">type.Name</param>
        ///// <param name="sTypeFilter">filter條件</param>
        ///// <returns>是否符合</returns>
        //private static bool TypeFilter(string sTypeName, string sTypeFilter)
        //{
        //    if (sTypeFilter.IsNullOrEmpty())
        //    {
        //        return true;
        //    }

        //    return Regex.IsMatch(sTypeName, sTypeFilter);
        //}

        //public List<Type> QueryObjectByClassAttribute(string sAssemblyFolderNamePath, Attribute aQueryAttribute)
        //{
        //    DirectoryInfo dirSpcPath = new DirectoryInfo(sAssemblyFolderNamePath);

        //    List<Type> lstReflectionItem = new List<Type>();
        //    Type attribute = aQueryAttribute.GetType();

        //    foreach (FileInfo fiDllFile in dirSpcPath.GetFiles("*.dll"))
        //    {
        //        try
        //        {
        //            Assembly loadAssembly = Assembly.LoadFile(fiDllFile.FullName);

        //            foreach (Type aType in loadAssembly.GetTypes())
        //            {
        //                if (aType.GetCustomAttributes(attribute, true).Length > 0)
        //                {
        //                    lstReflectionItem.Add(aType);
        //                }
        //            }
        //        }
        //        catch (BadImageFormatException)
        //        {
        //        }
        //        catch (ReflectionTypeLoadException)
        //        {
        //        }
        //    }

        //    return lstReflectionItem;
        //}

        ///// <summary>
        ///// 取得有該屬性的物件
        ///// </summary>
        ///// <param name="aQueryAttribute">屬性</param>
        ///// <returns>回傳的物件</returns>
        //public List<Type> QueryObjectByClassAttribute(Attribute aQueryAttribute)
        //{
        //    return QueryObjectByClassAttribute(AppDomain.CurrentDomain.BaseDirectory, aQueryAttribute);
        //}

        ///// <summary>
        ///// 到目前Assembly所在的目錄(bin),取出所有屬於該Type的Type資訊(使用LoadFrom)
        ///// </summary>
        ///// <param name="tQueryType">欲查詢的型別</param>
        ///// <returns>所有繼承或實作該型別的類別</returns>
        //public List<Type> QueryObjectLoadFromByType(Type tQueryType)
        //{
        //    //到目前Assembly所在的目錄(bin),取出Type為tQueryType的項目
        //    string sPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin\\");
        //    return QueryObjectLoadFromByType(sPath, tQueryType);
        //}

        ///// <summary>
        ///// 到指定的目錄,取出所有屬於該Type的Type資訊(使用LoadFrom)
        ///// </summary>
        ///// <param name="sAssemblyFolderNamePath">組件所在的目錄</param>
        ///// <param name="tQueryType">查詢的型別</param>
        ///// <returns>所有繼承或實作該型別的類別</returns>
        //public List<Type> QueryObjectLoadFromByType(string sAssemblyFolderNamePath, Type tQueryType)
        //{
        //    //到參數的目錄,取出Type為tQueryType的項目
        //    DirectoryInfo dirSpcPath = new DirectoryInfo(sAssemblyFolderNamePath);

        //    if (!dirSpcPath.Exists)
        //    {
        //        //throw new Exception(_Res.ReflectionManager_QueryObjectByType + sAssemblyFolderNamePath);
        //    }

        //    List<Type> lstReflectionItem = new List<Type>();

        //    //QQ Hugo [ReflectionDB] 1.請拋出路徑錯誤的的錯誤，需標明路徑 (Hunt)
        //    //QQ Hunt OK
        //    foreach (FileInfo fiDllFile in dirSpcPath.GetFiles("*.dll"))
        //    {
        //        try
        //        {
        //            Assembly loadAssembly = Assembly.LoadFrom(fiDllFile.FullName);

        //            foreach (Type aType in loadAssembly.GetTypes())
        //            {
        //                if (tQueryType.IsAssignableFrom(aType))
        //                {
        //                    lstReflectionItem.Add(aType);
        //                }
        //            }
        //        }
        //        catch (BadImageFormatException)
        //        {
        //            //理論上不是.NET DLL的，應該跑這個Exception
        //        }
        //        catch (ReflectionTypeLoadException)
        //        {
        //            //QQ Hugo [ReflectionDB] 1.此不明的錯誤會造成傳回結果上的錯誤嗎(應取得未取得)？ (Hunt)
        //            //QQ Hunt 有些.NET 的Dll載入時會拋出這個訊息
        //        }
        //    }

        //    return lstReflectionItem;
        //}
    }
}
